<!DOCTYPE HTML>
<!--
	Dimension by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
 <head>
  <title>
   Dimension by HTML5 UP
  </title>
  <!-- <meta charset="utf-8" /> -->
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> -->
  <meta charset="utf-8"/>
  <meta content="width=device-width,initial-scale=1.0" name="viewport"/>
  <link href="../../assets/css/article.css" rel="stylesheet"/>
  <link href="https://cdn.bootcss.com/highlight.js/9.15.8/styles/github.min.css" rel="stylesheet"/>
  <noscript>
   <link href="../../assets/css/noscript.css" rel="stylesheet"/>
  </noscript>
 </head>
 <body>
  <div id="app">
  </div>
  <!-- built files will be auto injected -->
 </body>
 <body class="is-preload">
  <!-- Wrapper -->
  <div id="wrapper">
   <!-- Main -->
   <div id="main">
    <article id="article">
     <h1 id="soulsoulspringmvcclient">
      Soul网关源码解析（二十三）SoulSpringMvcClient注解
     </h1>
     <hr/>
     <h2 id="_1">
      简介
     </h2>
     <p>
      本篇开始进入第三个模块：Soul-Client，这个模块负责自动注册路由相关的数据，本篇探索下HTTP服务注册的SoulSpringMvcClient注解
     </p>
     <h2 id="_2">
      概览
     </h2>
     <p>
      大家如果使用过NGINX或者运行或soul，大致应该能了解路由转发规则都是需要配置的，在Soul网关中，有两种配置方式：一是手动在Soul-Admin后台管理界面进行配置；二是在后台服务中加上注解，让其自动注册配置
     </p>
     <p>
      在前面文章中，我们也收到配置了一个divide插件的，需要配置选择器和规则，那在自动注册配置的注解中，是如果进行配置的？选择器、规则分别是如何获取和对应的，我们下面开始初步探索下
     </p>
     <h2 id="debug">
      源码Debug
     </h2>
     <h3 id="_3">
      寻找切入点
     </h3>
     <p>
      这是第一次分析，还没有概念，我们先从运行日志查看下有没有蛛丝马迹。运行soul-examples-http模块，我们发现打印了下面的日志
     </p>
     <div class="codehilite">
      <pre><span></span><code>o.d.s.client.common.utils.RegisterUtils  : http client register success: {"appName":"http","context":"/http","path":"/http/order/findById","pathDesc":"Find by id","rpcType":"http","host":"172.21.160.1","port":8188,"ruleName":"/http/order/findById","enabled":true,"registerMetaData":false} 
o.d.s.client.common.utils.RegisterUtils  : http client register success: {"appName":"http","context":"/http","path":"/http/order/save","pathDesc":"Save order","rpcType":"http","host":"172.21.160.1","port":8188,"ruleName":"/http/order/save","enabled":true,"registerMetaData":false} 
</code></pre>
     </div>
     <p>
      通过上面这个日志可以看出，这是注册成功的信息，是在RegisterUtils中进行的，我们搜索这个类，查看下：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">RegisterUtils</span> <span class="p">{</span>

    <span class="cm">/**</span>
<span class="cm">     * call register api.</span>
<span class="cm">     *</span>
<span class="cm">     * @param json        request body</span>
<span class="cm">     * @param url         url</span>
<span class="cm">     * @param rpcTypeEnum rcp type</span>
<span class="cm">     */</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">doRegister</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">json</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">url</span><span class="p">,</span> <span class="kd">final</span> <span class="n">RpcTypeEnum</span> <span class="n">rpcTypeEnum</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">try</span> <span class="p">{</span>
            <span class="c1">// 调用第三方的HTTP客户端发送post请求，url是Soul-Admin的地址加接口</span>
            <span class="n">String</span> <span class="n">result</span> <span class="o">=</span> <span class="n">OkHttpTools</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">post</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">json</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">AdminConstants</span><span class="p">.</span><span class="na">SUCCESS</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">result</span><span class="p">))</span> <span class="p">{</span>
                <span class="n">log</span><span class="p">.</span><span class="na">info</span><span class="p">(</span><span class="s">"{} client register success: {} "</span><span class="p">,</span> <span class="n">rpcTypeEnum</span><span class="p">.</span><span class="na">getName</span><span class="p">(),</span> <span class="n">json</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">log</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="s">"{} client register error: {} "</span><span class="p">,</span> <span class="n">rpcTypeEnum</span><span class="p">.</span><span class="na">getName</span><span class="p">(),</span> <span class="n">json</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">IOException</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">log</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="s">"cannot register soul admin param, url: {}, request body: {}"</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">json</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      通过上面的函数，可以看到这个就是注册配置的最后一站了，我们在上面的函数打上断点，跟踪调用栈
     </p>
     <p>
      重启后进入断点，来到下面的类，被下面的函数进行调用
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">SpringMvcClientBeanPostProcessor</span> <span class="kd">implements</span> <span class="n">BeanPostProcessor</span> <span class="p">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">Object</span> <span class="nf">postProcessAfterInitialization</span><span class="p">(</span><span class="nd">@NonNull</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">bean</span><span class="p">,</span> <span class="nd">@NonNull</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">beanName</span><span class="p">)</span> <span class="kd">throws</span> <span class="n">BeansException</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">controller</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">restController</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">requestMapping</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">SoulSpringMvcClient</span> <span class="n">clazzAnnotation</span> <span class="o">=</span> <span class="n">AnnotationUtils</span><span class="p">.</span><span class="na">findAnnotation</span><span class="p">(</span><span class="n">bean</span><span class="p">.</span><span class="na">getClass</span><span class="p">(),</span> <span class="n">SoulSpringMvcClient</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
            <span class="n">String</span> <span class="n">prePath</span> <span class="o">=</span> <span class="s">""</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">nonNull</span><span class="p">(</span><span class="n">clazzAnnotation</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">clazzAnnotation</span><span class="p">.</span><span class="na">path</span><span class="p">().</span><span class="na">indexOf</span><span class="p">(</span><span class="s">"*"</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">String</span> <span class="n">finalPrePath</span> <span class="o">=</span> <span class="n">prePath</span><span class="p">;</span>
                    <span class="n">executorService</span><span class="p">.</span><span class="na">execute</span><span class="p">(()</span> <span class="o">-&gt;</span> <span class="n">RegisterUtils</span><span class="p">.</span><span class="na">doRegister</span><span class="p">(</span><span class="n">buildJsonParams</span><span class="p">(</span><span class="n">clazzAnnotation</span><span class="p">,</span> <span class="n">finalPrePath</span><span class="p">),</span> <span class="n">url</span><span class="p">,</span>
                            <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">HTTP</span><span class="p">));</span>
                    <span class="k">return</span> <span class="n">bean</span><span class="p">;</span>
                <span class="p">}</span>
                <span class="n">prePath</span> <span class="o">=</span> <span class="n">clazzAnnotation</span><span class="p">.</span><span class="na">path</span><span class="p">();</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">bean</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      继续往下发现调用栈没了，我们在上面的函数中打上断点，重启查看调用栈，发现是Spring相关的，BeanPostProcessor是关键，大致是会在Bean初始化后会触发运行
     </p>
     <p>
      查阅参考的链接是：
      <a href="https://www.jianshu.com/p/e1c3c6e90e8a">
       Spring BeanPostProcessor接口使用
      </a>
     </p>
     <h3 id="_4">
      注册配置大致逻辑
     </h3>
     <p>
      在SpringMvcClientBeanPostProcessor的postProcessAfterInitialization函数上打上断点，会发现每个bean都会触发执行
     </p>
     <p>
      之前还猜测注册配置信息是使用AOP方式执行的，但只才对了一般，应该是使用AOP并且是在初始化的时候进行注册配置的，感觉自己对Spring还有好多不了解，后面得搞一下了
     </p>
     <p>
      在下面这个类中，初始化就有了Soul-Admin后台的url接口地址
     </p>
     <p>
      我们看它的注册逻辑是：
     </p>
     <ul>
      <li>
       1.如果类上有Controller、RestController、RequestMapping这三个注解之一，那将进行下一个Soul注解的判断注册
      </li>
      <li>
       2.如果是在类上有Soul的相关注解
      </li>
      <li>
       如果注解是通配符，将所有接口都进行注册
      </li>
      <li>
       如果不是，先得到接口前缀，获取所有方法，将方法上有Soul相关注解的都给注册上去
      </li>
     </ul>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">SpringMvcClientBeanPostProcessor</span> <span class="kd">implements</span> <span class="n">BeanPostProcessor</span> <span class="p">{</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="n">ThreadPoolExecutor</span> <span class="n">executorService</span><span class="p">;</span>

    <span class="c1">// http://localhost:9095/soul-client/springmvc-register</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">url</span><span class="p">;</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="n">SoulSpringMvcConfig</span> <span class="n">soulSpringMvcConfig</span><span class="p">;</span>

    <span class="cm">/**</span>
<span class="cm">     * Instantiates a new Soul client bean post processor.</span>
<span class="cm">     *</span>
<span class="cm">     * @param soulSpringMvcConfig the soul spring mvc config</span>
<span class="cm">     */</span>
    <span class="kd">public</span> <span class="nf">SpringMvcClientBeanPostProcessor</span><span class="p">(</span><span class="kd">final</span> <span class="n">SoulSpringMvcConfig</span> <span class="n">soulSpringMvcConfig</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">ValidateUtils</span><span class="p">.</span><span class="na">validate</span><span class="p">(</span><span class="n">soulSpringMvcConfig</span><span class="p">);</span>
        <span class="c1">// amdinUrl:http://localhost:9095</span>
        <span class="c1">// contextPath:/http</span>
        <span class="c1">// appName:http</span>
        <span class="c1">// full:false</span>
        <span class="c1">// host:null</span>
        <span class="c1">// port:8188</span>
        <span class="k">this</span><span class="p">.</span><span class="na">soulSpringMvcConfig</span> <span class="o">=</span> <span class="n">soulSpringMvcConfig</span><span class="p">;</span>
        <span class="n">url</span> <span class="o">=</span> <span class="n">soulSpringMvcConfig</span><span class="p">.</span><span class="na">getAdminUrl</span><span class="p">()</span> <span class="o">+</span> <span class="s">"/soul-client/springmvc-register"</span><span class="p">;</span>
        <span class="n">executorService</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ThreadPoolExecutor</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="n">L</span><span class="p">,</span> <span class="n">TimeUnit</span><span class="p">.</span><span class="na">MILLISECONDS</span><span class="p">,</span> <span class="k">new</span> <span class="n">LinkedBlockingQueue</span><span class="o">&lt;&gt;</span><span class="p">());</span>
    <span class="p">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="n">Object</span> <span class="nf">postProcessAfterInitialization</span><span class="p">(</span><span class="nd">@NonNull</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">bean</span><span class="p">,</span> <span class="nd">@NonNull</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">beanName</span><span class="p">)</span> <span class="kd">throws</span> <span class="n">BeansException</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">soulSpringMvcConfig</span><span class="p">.</span><span class="na">isFull</span><span class="p">())</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">bean</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="c1">// 判断是否有下面三个HTTP注解之一</span>
        <span class="n">Controller</span> <span class="n">controller</span> <span class="o">=</span> <span class="n">AnnotationUtils</span><span class="p">.</span><span class="na">findAnnotation</span><span class="p">(</span><span class="n">bean</span><span class="p">.</span><span class="na">getClass</span><span class="p">(),</span> <span class="n">Controller</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
        <span class="n">RestController</span> <span class="n">restController</span> <span class="o">=</span> <span class="n">AnnotationUtils</span><span class="p">.</span><span class="na">findAnnotation</span><span class="p">(</span><span class="n">bean</span><span class="p">.</span><span class="na">getClass</span><span class="p">(),</span> <span class="n">RestController</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
        <span class="n">RequestMapping</span> <span class="n">requestMapping</span> <span class="o">=</span> <span class="n">AnnotationUtils</span><span class="p">.</span><span class="na">findAnnotation</span><span class="p">(</span><span class="n">bean</span><span class="p">.</span><span class="na">getClass</span><span class="p">(),</span> <span class="n">RequestMapping</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">controller</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">restController</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">requestMapping</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">SoulSpringMvcClient</span> <span class="n">clazzAnnotation</span> <span class="o">=</span> <span class="n">AnnotationUtils</span><span class="p">.</span><span class="na">findAnnotation</span><span class="p">(</span><span class="n">bean</span><span class="p">.</span><span class="na">getClass</span><span class="p">(),</span> <span class="n">SoulSpringMvcClient</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
            <span class="n">String</span> <span class="n">prePath</span> <span class="o">=</span> <span class="s">""</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">nonNull</span><span class="p">(</span><span class="n">clazzAnnotation</span><span class="p">))</span> <span class="p">{</span>
                <span class="c1">// 类上有注解，且是通配符，以通配符方式进行注册,RPCType直接定死为HTTP</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">clazzAnnotation</span><span class="p">.</span><span class="na">path</span><span class="p">().</span><span class="na">indexOf</span><span class="p">(</span><span class="s">"*"</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
                    <span class="n">String</span> <span class="n">finalPrePath</span> <span class="o">=</span> <span class="n">prePath</span><span class="p">;</span>
                    <span class="n">executorService</span><span class="p">.</span><span class="na">execute</span><span class="p">(()</span> <span class="o">-&gt;</span> <span class="n">RegisterUtils</span><span class="p">.</span><span class="na">doRegister</span><span class="p">(</span><span class="n">buildJsonParams</span><span class="p">(</span><span class="n">clazzAnnotation</span><span class="p">,</span> <span class="n">finalPrePath</span><span class="p">),</span> <span class="n">url</span><span class="p">,</span>
                            <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">HTTP</span><span class="p">));</span>
                    <span class="k">return</span> <span class="n">bean</span><span class="p">;</span>
                <span class="p">}</span>
                <span class="n">prePath</span> <span class="o">=</span> <span class="n">clazzAnnotation</span><span class="p">.</span><span class="na">path</span><span class="p">();</span>
            <span class="p">}</span>
            <span class="c1">// 遍历所有的方法，注册上面有Soul相关注解的方法</span>
            <span class="kd">final</span> <span class="n">Method</span><span class="o">[]</span> <span class="n">methods</span> <span class="o">=</span> <span class="n">ReflectionUtils</span><span class="p">.</span><span class="na">getUniqueDeclaredMethods</span><span class="p">(</span><span class="n">bean</span><span class="p">.</span><span class="na">getClass</span><span class="p">());</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">Method</span> <span class="n">method</span> <span class="p">:</span> <span class="n">methods</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">SoulSpringMvcClient</span> <span class="n">soulSpringMvcClient</span> <span class="o">=</span> <span class="n">AnnotationUtils</span><span class="p">.</span><span class="na">findAnnotation</span><span class="p">(</span><span class="n">method</span><span class="p">,</span> <span class="n">SoulSpringMvcClient</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">nonNull</span><span class="p">(</span><span class="n">soulSpringMvcClient</span><span class="p">))</span> <span class="p">{</span>
                    <span class="n">String</span> <span class="n">finalPrePath</span> <span class="o">=</span> <span class="n">prePath</span><span class="p">;</span>
                    <span class="n">executorService</span><span class="p">.</span><span class="na">execute</span><span class="p">(()</span> <span class="o">-&gt;</span> <span class="n">RegisterUtils</span><span class="p">.</span><span class="na">doRegister</span><span class="p">(</span><span class="n">buildJsonParams</span><span class="p">(</span><span class="n">soulSpringMvcClient</span><span class="p">,</span> <span class="n">finalPrePath</span><span class="p">),</span> <span class="n">url</span><span class="p">,</span>
                            <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">HTTP</span><span class="p">));</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">bean</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// 构造请求内容</span>
    <span class="kd">private</span> <span class="n">String</span> <span class="nf">buildJsonParams</span><span class="p">(</span><span class="kd">final</span> <span class="n">SoulSpringMvcClient</span> <span class="n">soulSpringMvcClient</span><span class="p">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">prePath</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">contextPath</span> <span class="o">=</span> <span class="n">soulSpringMvcConfig</span><span class="p">.</span><span class="na">getContextPath</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">appName</span> <span class="o">=</span> <span class="n">soulSpringMvcConfig</span><span class="p">.</span><span class="na">getAppName</span><span class="p">();</span>
        <span class="n">Integer</span> <span class="n">port</span> <span class="o">=</span> <span class="n">soulSpringMvcConfig</span><span class="p">.</span><span class="na">getPort</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">path</span> <span class="o">=</span> <span class="n">contextPath</span> <span class="o">+</span> <span class="n">prePath</span> <span class="o">+</span> <span class="n">soulSpringMvcClient</span><span class="p">.</span><span class="na">path</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">desc</span> <span class="o">=</span> <span class="n">soulSpringMvcClient</span><span class="p">.</span><span class="na">desc</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">configHost</span> <span class="o">=</span> <span class="n">soulSpringMvcConfig</span><span class="p">.</span><span class="na">getHost</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">host</span> <span class="o">=</span> <span class="n">StringUtils</span><span class="p">.</span><span class="na">isBlank</span><span class="p">(</span><span class="n">configHost</span><span class="p">)</span> <span class="o">?</span> <span class="n">IpUtils</span><span class="p">.</span><span class="na">getHost</span><span class="p">()</span> <span class="p">:</span> <span class="n">configHost</span><span class="p">;</span>
        <span class="n">String</span> <span class="n">configRuleName</span> <span class="o">=</span> <span class="n">soulSpringMvcClient</span><span class="p">.</span><span class="na">ruleName</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">ruleName</span> <span class="o">=</span> <span class="n">StringUtils</span><span class="p">.</span><span class="na">isBlank</span><span class="p">(</span><span class="n">configRuleName</span><span class="p">)</span> <span class="o">?</span> <span class="n">path</span> <span class="p">:</span> <span class="n">configRuleName</span><span class="p">;</span>
        <span class="n">SpringMvcRegisterDTO</span> <span class="n">registerDTO</span> <span class="o">=</span> <span class="n">SpringMvcRegisterDTO</span><span class="p">.</span><span class="na">builder</span><span class="p">()</span>
                <span class="p">.</span><span class="na">context</span><span class="p">(</span><span class="n">contextPath</span><span class="p">)</span>
                <span class="p">.</span><span class="na">host</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
                <span class="p">.</span><span class="na">port</span><span class="p">(</span><span class="n">port</span><span class="p">)</span>
                <span class="p">.</span><span class="na">appName</span><span class="p">(</span><span class="n">appName</span><span class="p">)</span>
                <span class="p">.</span><span class="na">path</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
                <span class="p">.</span><span class="na">pathDesc</span><span class="p">(</span><span class="n">desc</span><span class="p">)</span>
                <span class="p">.</span><span class="na">rpcType</span><span class="p">(</span><span class="n">soulSpringMvcClient</span><span class="p">.</span><span class="na">rpcType</span><span class="p">())</span>
                <span class="p">.</span><span class="na">enabled</span><span class="p">(</span><span class="n">soulSpringMvcClient</span><span class="p">.</span><span class="na">enabled</span><span class="p">())</span>
                <span class="p">.</span><span class="na">ruleName</span><span class="p">(</span><span class="n">ruleName</span><span class="p">)</span>
                <span class="p">.</span><span class="na">registerMetaData</span><span class="p">(</span><span class="n">soulSpringMvcClient</span><span class="p">.</span><span class="na">registerMetaData</span><span class="p">())</span>
                <span class="p">.</span><span class="na">build</span><span class="p">();</span>
        <span class="k">return</span> <span class="n">OkHttpTools</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">getGson</span><span class="p">().</span><span class="na">toJson</span><span class="p">(</span><span class="n">registerDTO</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <h3 id="_5">
      注册配置信息来源
     </h3>
     <p>
      我们来大致看一下那些注册信息的来源
     </p>
     <p>
      下面这个是一个需要注册的接口：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nd">@RestController</span>
<span class="nd">@RequestMapping</span><span class="p">(</span><span class="s">"/order"</span><span class="p">)</span>
<span class="nd">@SoulSpringMvcClient</span><span class="p">(</span><span class="n">path</span> <span class="o">=</span> <span class="s">"/order"</span><span class="p">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">OrderController</span> <span class="p">{</span>

    <span class="nd">@PostMapping</span><span class="p">(</span><span class="s">"/save"</span><span class="p">)</span>
    <span class="nd">@SoulSpringMvcClient</span><span class="p">(</span><span class="n">path</span> <span class="o">=</span> <span class="s">"/save"</span> <span class="p">,</span> <span class="n">desc</span> <span class="o">=</span> <span class="s">"Save order"</span><span class="p">)</span>
    <span class="kd">public</span> <span class="n">OrderDTO</span> <span class="nf">save</span><span class="p">(</span><span class="nd">@RequestBody</span> <span class="kd">final</span> <span class="n">OrderDTO</span> <span class="n">orderDTO</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">orderDTO</span><span class="p">.</span><span class="na">setName</span><span class="p">(</span><span class="s">"hello world save order"</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">orderDTO</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      这个是soul相关的配置文件：
     </p>
     <div class="codehilite">
      <pre><span></span><code>soul:
  http:
    adminUrl: http://localhost:9095
    port: 8188
    contextPath: /http
    appName: http
    full: false
</code></pre>
     </div>
     <p>
      下面这个是POST的内容，我们可以看到：AppName、context、port都是从配置中获取
     </p>
     <p>
      path、pathDesc、RPCType等等都在在程序注解中获取的（SoulSpringMvcClient），enabled默认值是true
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="p">{</span>
    <span class="nt">"appName"</span><span class="p">:</span> <span class="s2">"http"</span><span class="p">,</span>
    <span class="nt">"context"</span><span class="p">:</span> <span class="s2">"/http"</span><span class="p">,</span>
    <span class="nt">"path"</span><span class="p">:</span> <span class="s2">"/http/order/save"</span><span class="p">,</span>
    <span class="nt">"pathDesc"</span><span class="p">:</span> <span class="s2">"Save order"</span><span class="p">,</span>
    <span class="nt">"rpcType"</span><span class="p">:</span> <span class="s2">"http"</span><span class="p">,</span>
    <span class="nt">"host"</span><span class="p">:</span> <span class="s2">"172.21.160.1"</span><span class="p">,</span>
    <span class="nt">"port"</span><span class="p">:</span> <span class="mi">8188</span><span class="p">,</span>
    <span class="nt">"ruleName"</span><span class="p">:</span> <span class="s2">"/http/order/save"</span><span class="p">,</span>
    <span class="nt">"enabled"</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
    <span class="nt">"registerMetaData"</span><span class="p">:</span> <span class="kc">false</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      简单去看一下Soul-Admin的接口处理函数，可以看到是从传入的数据中进行选择器和规则的处理，和我们想象的差不多（这里深入下去代码太多了，就不详解，CRUD大家应该看起来没得问题),需要注意的是，在处理的过程中会触发事件发布，进一步验证了Controller是数据同步事件的触发入口
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">SoulClientRegisterServiceImpl</span> <span class="kd">implements</span> <span class="n">SoulClientRegisterService</span> <span class="p">{</span>
    <span class="nd">@Override</span>
    <span class="nd">@Transactional</span>
    <span class="kd">public</span> <span class="n">String</span> <span class="nf">registerSpringMvc</span><span class="p">(</span><span class="kd">final</span> <span class="n">SpringMvcRegisterDTO</span> <span class="n">dto</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">dto</span><span class="p">.</span><span class="na">isRegisterMetaData</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">MetaDataDO</span> <span class="n">exist</span> <span class="o">=</span> <span class="n">metaDataMapper</span><span class="p">.</span><span class="na">findByPath</span><span class="p">(</span><span class="n">dto</span><span class="p">.</span><span class="na">getPath</span><span class="p">());</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">exist</span><span class="p">))</span> <span class="p">{</span>
                <span class="n">saveSpringMvcMetaData</span><span class="p">(</span><span class="n">dto</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="c1">// 处理选择器</span>
        <span class="n">String</span> <span class="n">selectorId</span> <span class="o">=</span> <span class="n">handlerSpringMvcSelector</span><span class="p">(</span><span class="n">dto</span><span class="p">);</span>
        <span class="c1">// 处理规则</span>
        <span class="n">handlerSpringMvcRule</span><span class="p">(</span><span class="n">selectorId</span><span class="p">,</span> <span class="n">dto</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">SoulResultMessage</span><span class="p">.</span><span class="na">SUCCESS</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <h2 id="_6">
      总结
     </h2>
     <p>
      本篇初步探索了下Soul-Client的HTTP注册注解，了解了注册的大致流程：
     </p>
     <ul>
      <li>
       1.如果类上有Controller、RestController、RequestMapping这三个注解之一，那将进行下一个Soul注解的判断注册
      </li>
      <li>
       2.如果是在类上有Soul的相关注解
      </li>
      <li>
       如果注解是通配符，将所有接口都进行注册
      </li>
      <li>
       如果不是，先得到接口前缀，获取所有方法，将方法上有Soul相关注解的都给注册上去
      </li>
     </ul>
     <p>
      注册的信息基本都是从配置文件和注解中进行获取的
     </p>
     <p>
      注册的内容是相应的选择器和规则
     </p>
     <h2 id="soul">
      Soul网关源码解析文章列表
     </h2>
     <h3 id="_7">
      掘金
     </h3>
     <h4 id="_8">
      了解与初步运行
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6917864624423436296">
        Soul网关源码解析（一） 概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917865804121767944">
        Soul网关源码解析（二）代码初步运行
       </a>
      </li>
     </ul>
     <h4 id="_9">
      请求处理流程解析
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6917866538712334343">
        Soul网关源码解析（三）请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917867369909977102">
        Soul网关源码解析（四）Dubbo请求概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918575905962983438">
        Soul网关源码解析（五）请求类型探索
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918736260467015693">
        Soul网关源码解析（六）Sofa请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6919348164944232455/">
        Soul网关源码解析（七）限流插件初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6919774553241550855/">
        Soul网关源码解析（八）路由匹配初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920074307590684685/">
        Soul网关源码解析（九）插件配置加载初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920142348617777166">
        Soul网关源码解析（十）自定义简单插件编写
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920596034171174925">
        Soul网关源码解析（十一）请求处理小结
       </a>
      </li>
     </ul>
     <h4 id="_10">
      数据同步解析
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6920596173925384206">
        Soul网关源码解析（十二）数据同步初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920596028505178125">
        Soul网关源码解析（十三）Websocket同步数据-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920597298674302983">
        Soul网关源码解析（十四）HTTP数据同步-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920764643967238151">
        Soul网关源码解析（十五）Zookeeper数据同步-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921170233868845064">
        Soul网关源码解析（十六）Nacos数据同步示例运行
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921325882753695757/">
        Soul网关源码解析（十七）Nacos数据同步解析-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921495273122463751/">
        Soul网关源码解析（十八）Zookeeper数据同步初探-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921621915995996168/">
        Soul网关源码解析（十九）Nacos数据同步初始化修复-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921988280187617287/">
        Soul网关源码解析（二十）Websocket数据同步-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922301585288593416/">
        Soul网关源码解析（二十一）HTTP长轮询数据同步-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922584596810825735/">
        Soul网关源码解析（二十二）数据同步小结
       </a>
      </li>
     </ul>
     <h4 id="soul-client">
      Soul-Client模块
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6922643958455599111">
        Soul网关源码解析（二十三）SoulSpringMvcClient注解
       </a>
      </li>
     </ul>
     <h4 id="_11">
      番外
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6918947689564471309">
        Soul网关源码阅读番外篇（一） HTTP参数请求错误
       </a>
      </li>
     </ul>
    </article>
   </div>
   <!-- Footer -->
   <footer id="footer">
    <p class="copyright">
     © Untitled. Design:
     <a href="https://html5up.net">
      HTML5 UP
     </a>
     .
    </p>
   </footer>
  </div>
  <!-- BG -->
  <div id="bg">
  </div>
  <!-- Scripts -->
  <script src="../assets/js/jquery.min.js">
  </script>
  <script src="../assets/js/browser.min.js">
  </script>
  <script src="../assets/js/breakpoints.min.js">
  </script>
  <script src="../assets/js/util.js">
  </script>
  <script src="../assets/js/main.js">
  </script>
 </body>
</html>
